#include "gpio.h"
#include "func_gpio.h"
#include "my_timer.h"
#include "usb_com.h"
typedef struct func_gpio
{

    unsigned short firstTick;
    unsigned short secondTick;
    unsigned short firstHoldTime;
    unsigned short secondHoldTime;
    unsigned short repeatTimes;
    unsigned char startLevel: 1;
    unsigned char level: 1;
    unsigned char needRun: 1;
    unsigned char runStep;
    unsigned char readOk: 1;
    unsigned char ID: 3;
} func_gpio;

func_gpio gpios[4];


static const unsigned short pinMap[] = {GPIO_PIN_4, GPIO_PIN_5, GPIO_PIN_10, GPIO_PIN_11};
struct my_timer gpio_timer;

static void gpio_loop(void *p)
{
    for (int i = 0; i < 4; i++)
    {
        if (gpios[i].needRun)
        {
            if (gpios[i].runStep == 0)
            {
                HAL_GPIO_WritePin(GPIOB, pinMap[gpios[i].ID], gpios[i].startLevel);
                gpios[i].firstTick++;
                if(gpios[i].firstTick >= gpios[i].firstHoldTime)
                {
                    gpios[i].runStep = 1;
                    gpios[i].secondTick = 0;
                }
            }
            else
            {
                HAL_GPIO_WritePin(GPIOB, pinMap[gpios[i].ID], !gpios[i].startLevel);
                gpios[i].secondTick++;
                if(gpios[i].secondTick >= gpios[i].secondHoldTime)
                {
                    gpios[i].runStep = 0;
                    gpios[i].firstTick = 0;
                    if(gpios[i].repeatTimes)
                    {
                        gpios[i].repeatTimes--;
                        if(gpios[i].repeatTimes == 0)
                        {
                            gpios[i].needRun = 0;
                        }
                    }
                }
            }
        }
    }
}


void gpio_init()
{
    for (int i = 0; i < 4; i++)
    {
        gpios[i].ID = i;
    }
    timer_register_set(&gpio_timer, 1, 0, 0, gpio_loop, 0, 1);
}

void gpio_mode_set(unsigned char cmd, unsigned char subCmd, unsigned char *data)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if (data[5] >= sizeof(pinMap) / sizeof(pinMap[0]))
    {
        usb_cmd(COMM_GPIO, COMM_SUB_GPIO_PIN_SET, (void *)COM_FAIL);
        return;
    }

    GPIO_InitStruct.Pin = pinMap[data[5]];

    switch (data[6])
    {
        case 0:
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            break;
        case 1:
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_PULLUP;
            break;
        case 2:
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_PULLDOWN;
            break;
        case 3:
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            break;
        case 4:
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            break;

        default:
            usb_cmd(COMM_GPIO, COMM_SUB_GPIO_PIN_SET, (void *)COM_FAIL);
            return;
    }

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    usb_cmd(COMM_GPIO, COMM_SUB_GPIO_PIN_SET, (void *)COM_OK);
}
void gpio_more_hl(unsigned char cmd, unsigned char subCmd, unsigned char *b)
{
    if (b[5] >= 4)
    {
        usb_cmd(COMM_GPIO, COMM_SUB_GPIO_HL_CHANGE, (void *)COM_FAIL);
        return;
    }
    gpios[b[5]].startLevel = b[6];
    gpios[b[5]].firstHoldTime = (b[7] << 8) + b[8];
    gpios[b[5]].secondHoldTime = (b[9] << 8) + b[10];
    gpios[b[5]].repeatTimes = (b[11] << 8) + b[12];

    gpios[b[5]].needRun = 1;
    gpios[b[5]].firstTick = 0;
    gpios[b[5]].runStep = 0;
    usb_cmd(COMM_GPIO, COMM_SUB_GPIO_HL_CHANGE, (void *)COM_OK);
}
void gpio_set_level(unsigned char cmd, unsigned char subCmd, unsigned char *b)
{
    if (b[5] >= sizeof(pinMap) / sizeof(pinMap[0]))
    {
        usb_cmd(COMM_GPIO, COMM_SUB_GPIO_PIN_SET, (void *)COM_FAIL);
        return;
    }
    HAL_GPIO_WritePin(GPIOB, pinMap[b[5]], b[6] == 1 ? GPIO_PIN_SET : GPIO_PIN_RESET);
    usb_cmd(COMM_GPIO, COMM_SUB_GPIO_LEVEL_SET, (void *)COM_OK);

}
void gpio_read_level(unsigned char cmd, unsigned char subCmd, unsigned char *b)
{
    if (b[5] >= 4)
    {
        usb_cmd(COMM_GPIO, COMM_SUB_GPIO_LEVEL_READ, 0);
        return;
    }
    gpios[b[5]].readOk = 0;
    gpios[b[5]].level = HAL_GPIO_ReadPin(GPIOB, pinMap[b[5]]);

    usb_cmd(COMM_GPIO, COMM_SUB_GPIO_LEVEL_READ, (void *)&gpios[b[5]]);
}

/// @brief usb上传接收到的数据
/// @param cmd
/// @param subCmd
/// @param param
void gpio_read_level_update(unsigned char cmd, unsigned char subCmd, void *param)
{
    func_gpio *gp = (func_gpio *)param;
    unsigned char sendData[USB_PORT_SIZE] = {0};
    sendData[0] = 0xaa;
    sendData[1] = 0x55;
    sendData[2] = 9;
    sendData[3] = COMM_GPIO;
    sendData[4] = COMM_SUB_GPIO_LEVEL_READ;
    if (param == 0)
    {
        sendData[5] = 1;
        sendData[6] = 0;
        sendData[7] = 0;
    }
    else
    {
        sendData[5] = 0;
        sendData[6] = gp->ID;
        sendData[7] = gp->level;
    }

    sendData[8] = chksum(sendData, 8);
    usb_send(sendData, 9);
}
